﻿using System;
using System.Collections.Generic;
using System.Windows.Media;

using Bling.Core;
using Bling.DSL;
using Bling.WPF;
using Bling.Graphics;
using Bling.DX;
using Bling.Matrices;
using Bling.WPF3D;
using Bling.Shaders;

namespace Bling.Example {
  public class Diffusion : HasHost {
    public Diffusion()
      // by passing true to base, an overlay window will be created.
      : base(true) {
      int Dim = 500;
      Host.Size = new PointBl(Dim, Dim); // host size must be constant!
      Host.LeftTop = 0d;
      // background of overlay can't be transparent or it won't receive input. It can be a very transparent color though, go fig. 
      OverlayContent.Background = new SolidColorBrushBl() { Color = Colors.White, Opacity = OverlayContent.IsMouseOver.Condition(.15d, .01d), };

      var RenderTargetA = new RenderTargetTexture<D2>(Dim, Dim) {
        Format = new TextureFormat.Typical() {
          Width = TextureFormat.ChannelWidth.WORD,
          Type = TextureFormat.ChannelType.FLOAT,
        },
      };
      var RenderTargetB = new RenderTargetTexture<D2>(Dim,Dim) {
        Format = new TextureFormat.Typical() {
          Width = TextureFormat.ChannelWidth.WORD,
          Type = TextureFormat.ChannelType.FLOAT,
        },
      };
      RenderTargetBl RenderA = RenderTargetA.AsRenderTarget, RenderB = RenderTargetB.AsRenderTarget;
      TextureBl TextureA = RenderTargetA, TextureB = RenderTargetB;

      bool SwapFromTo0 = true;
      var Swap = true.Bl().StatefulMap<bool, BoolBl>(b => SwapFromTo0);
      var Face = new FaceTopology();
      { // handle the mouse
        var MouseOverContent = OverlayContent.MousePosition / OverlayContent.Size;
        MouseOverContent = MouseOverContent * 2d - 1d;
        MouseOverContent = MouseOverContent * new PointBl(+1, -1);

        var re = Device.Render(Face.Count, (n, vertex) => {
          var Transform = MouseOverContent.InsertZ(0).Translate() * .1d.Bl().XXX().Scale();
          vertex.Position = Transform.Transform((Point3DBl)Face[n]);
          vertex.Color = Colors.Red;
        }, Face.IndexBuffer);
        re.Target = Swap.Condition(RenderA, RenderB);
      }
      {
        var ColorsX = new Color[] {
          Colors.Red, Colors.Orange, Colors.Salmon, Colors.Pink,
        };
        var re = Device.Render(Face.Count, 4, (n, m, vertex) => {
          PointBl dxy = new PointBl(m % 2, m / 2);
          dxy = dxy * 2d - 1d;
          dxy = dxy * .7;

          var Transform = dxy.InsertZ(0).Translate() * .1d.Bl().XXX().Scale();
          vertex.Position = Transform.Transform((Point3DBl)Face[n]);
          vertex.Color = new TableExpr2<Color>(ColorsX, m.Underlying);
        }, Face.IndexBuffer);
        re.Target = Swap.Condition(RenderA, RenderB);
      }

      var Radius = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = Host.LeftBottom,
        LabelName = "Radius",
        Minimum = .001,
        Maximum = .020,
        Value = .009,
      };
      var M = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = Radius.LeftBottom,
        LabelName = "M",
        Minimum = .0,
        Maximum = .3,
        Value = .1,
      };
      var N = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = M.LeftBottom,
        LabelName = "N",
        Minimum = .0,
        Maximum = .003,
        Value = .001,
      };

      { // diffusion
        var re = Device.Render(Face.Count, (n, vertex) => {
          vertex.Position = (Point4DBl)Face[n];
          var uv = Face[n];
          uv = uv * new PointBl(+1, -1);
          uv = (uv + 1d) / 2d;
          var Tex = Swap.Condition(TextureA, TextureB);

          //var clr = Radius.Value.PerPixel().Diffusion(20)[Tex][uv];
          var clr = ShaderLib.Sample(Tex, uv, Radius.Value.PerPixel(), 20);
          clr = ShaderLib.Transfer(Tex[uv].ScRGB, clr, M.Value.PerPixel(), N.Value.PerPixel());
          clr = clr.Saturate;

          vertex.Color = clr.Saturate;
          
        }, Face.IndexBuffer);
        re.Target = Swap.Condition(RenderB, RenderA);
      }
      {
        var re = Device.Render(Face.Count, (n, vertex) => {
          vertex.Position = (Point4DBl)Face[n];
          var uv = Face[n];
          uv = uv * new PointBl(+1, -1);
          uv = (uv + 1d) / 2d;
          vertex.Color = Swap.Condition(TextureB, TextureA)[uv];
        }, Face.IndexBuffer);

        re.Post = () => SwapFromTo0 = !SwapFromTo0;
      }

      /*
      var RenderTargetB = new RenderTargetTexture<D2>(Width, Height) {
        Format = new TextureFormat.Typical() {
          Width = TextureFormat.ChannelWidth.WORD,
          Type = TextureFormat.ChannelType.FLOAT,
        },
      };*/

    }
  }
}
